from math import *
import numpy as np


def load_data_set():
    posting_list = [['my', 'dog', 'has', 'flea', 'problem', 'help', 'please'],
                    ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                    ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                    ['stop', 'posting', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                    ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                    ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    class_vec = [0, 1, 0, 1, 0, 1]
    return posting_list, class_vec


# 定义一个简单的文本数据集，由6个简单的文本以及对应的标签构成。1表示侮辱性文档，0表示正常文档。
def create_vocab_list(data_set):
    vocab_set = set([])
    for document in data_set:
        vocab_set = vocab_set | set(document)
    return list(vocab_set)


def set_of_words2_vec(vocab_list, input_set):
    return_vec = [0] * len(vocab_list)  # 每个文档的大小与词典保持一致，此时returnvec是空表
    for word in input_set:
        if word in vocab_list:
            return_vec[vocab_list.index(word)] = 1  # 当前文档中有某个词条，则根据词典获取其位置并赋值1
        else:
            print("the word :%s is not in my vocabulary" % word)
    return return_vec


def bag_of_words2_vec(vocab_list, input_set):
    return_vec = [0] * len(vocab_list)
    for word in input_set:
        if word in vocab_list:
            return_vec[vocab_list.index(word)] += 1  # 与词集模型的唯一区别就表现在这里
        else:
            print
        "the word :%s is not in my vocabulary" % word
    return return_vec


# 文档向量化，这里是词袋模型，不知关心某个词条出现与否，还考虑该词条在本文档中的出现频率

def train_nb(train_matrix, train_category):
    num_train_docs = len(train_matrix)
    num_words = len(train_matrix[0])
    p_abusive = sum(train_category) / float(num_train_docs)  # 统计侮辱性文档的总个数，然后除以总文档个数
    # p0num=zeros(numwords);p1num=zeros(numwords)    # 把属于同一类的文本向量加起来
    # p0denom=0.0;p1denom=0.0
    p0_num = np.ones(num_words);
    p1_num = np.ones(num_words)
    p0_denom = 2.0;
    p1_denom = 2.0
    for i in range(num_train_docs):
        if train_category[i] == 1:
            p1_num += train_matrix[i]  # 把属于同一类的文本向量相加，实质是统计某个词条在该类文本中出现频率
            p1_denom += sum(train_matrix[i])  # 把侮辱性文档向量的所有元素加起来
        else:
            p0_num += train_matrix[i]
            p0_denom += sum(train_matrix[i])
            # p1vec=p1num/float(p1denom)
    # p0vec=p0num/float(p0denom)
    p1_vec = log(p1_num / p1_denom)  # 统计词典中所有词条在侮辱性文档中出现的概率
    p0_vec = log(p0_num / p0_denom)  # 统计词典中所有词条在正常文档中出现的概率
    return p_abusive, p1_vec, p0_vec


# 训练生成朴素贝叶斯模型，实质上相当于是计算p（x，y|ci）p（ci）的权重。
# 注意：被注释掉的代码代表不太好的初始化方式，在那种情况下某些词条的概率值可能会非常非常小，甚至约
# 等于0，那么在不同词条的概率在相乘时结果就近似于0
def classify_nb(vec2_classify, p0_vec, p1_vec, p_class1):  # 参数1是测试文档向量，参数2和参数3是词条在各个
    # 类别中出现的概率，参数4是p（c1）
    p1 = sum(vec2_classify * p1_vec) + log(p_class1)  # 这里没有直接计算p（x，y|c1）p（c1），而是取其对数
    # 这样做也是防止概率之积太小，以至于为0
    p0 = sum(vec2_classify * p0_vec) + log(1.0 - p_class1)  # 取对数后虽然p（c1|x，y）和p(c0|x，y)的值变了，但是
    # 不影响它们的大小关系。
    if p1 > p0:
        return 1
    else:
        return 0


if __name__ == "__main__":
    data_set, class_vec = load_data_set()
    vocab_set = create_vocab_list(data_set)
